package com.ideaaedi.springcloud.jd.commonspring.mybatisplus.tenant;

import com.alibaba.fastjson2.JSON;
import com.ideaaedi.springcloud.jd.commonds.constant.BaseConstant;
import com.ideaaedi.springcloud.jd.commonds.constant.JdSymbolConstant;
import lombok.Getter;
import lombok.ToString;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Triple;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;

import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ConcurrentLinkedDeque;

/**
 * 临时租户实体类模型支持
 *
 * @author <font size = "20" color = "#3CAA3C"><a href="https://gitee.com/JustryDeng">JustryDeng</a></font> <img
 * src="https://gitee.com/JustryDeng/shared-files/raw/master/JustryDeng/avatar.jpg" />
 * @since 2021.0.5.B
 */
@Getter
@ToString
public class TenantDataScopeBO {
    
    /**
     * 特殊标识， 当为CURD中的UPDATE READ DELETE时，忽略租户及数据隔离
     */
    public static final String IGNORE_URD = "<IGNORE_TENANT&DATA-SCOPE_WHILE_URD>";
    
    /** 队列 */
    @Getter
    private final ConcurrentLinkedDeque<String> tenantDeque = new ConcurrentLinkedDeque<>();
    
    public TenantDataScopeBO(String tenantDataScopeStr) {
        tenantDeque.addFirst(tenantDataScopeStr);
    }
    
    /**
     * 构建TenantDataScope信息字符串
     *
     * @param tenant 租户信息
     * @param readDataScopePaths 可读数据范围的deptId对应的deptPath
     * @param updateDataScopePaths 可写(修改/删除)数据范围的deptId对应的deptPath
     *
     * @return TenantDataScope信息字符串
     */
    public static String buildTenantDataScopeStr(@NonNull String tenant, @Nullable Collection<String> readDataScopePaths,
                                                 @Nullable Collection<String> updateDataScopePaths) {
        Objects.requireNonNull(tenant, "tenant cannot be null.");
        if (IGNORE_URD.equals(tenant)) {
            return IGNORE_URD;
        }
        return String.join(JdSymbolConstant.PIPE, tenant,
                readDataScopePaths == null ? BaseConstant.EMPTY : JSON.toJSONString(readDataScopePaths),
                updateDataScopePaths == null ? BaseConstant.EMPTY : JSON.toJSONString(updateDataScopePaths));
    }
    
    /**
     * 从TenantDataScope信息字符串字符串中抽取信息
     *
     * @param tenantDataScopeStr TenantDataScope信息字符串
     *
     * @return <ul>
     *     <li>左(NonNull)-租户信息</li>
     *     <li>中(Nullable)-可读数据范围的deptId对应的deptPath</li>
     *     <li>右(Nullable)-可写(修改/删除)数据范围的deptId对应的deptPath</li>
     * </ul>
     */
    public static Triple<String, List<String>, List<String>> extractTenantDataScopeStr(@NonNull String tenantDataScopeStr) {
        Objects.requireNonNull(tenantDataScopeStr, "tenant cannot be null.");
        if (IGNORE_URD.equals(tenantDataScopeStr)) {
            return Triple.of(IGNORE_URD, null, null);
        }
        String[] itemArr = tenantDataScopeStr.split("\\|");
        if (itemArr.length < 1) {
            throw new IllegalArgumentException("cannot extract tenant from tenantDataScopeStr -> " + tenantDataScopeStr);
        }
        String tenant = itemArr[0];
        Objects.requireNonNull(tenant, "extracted tenant is null. tenantDataScopeStr -> " + tenantDataScopeStr);
        tenant = tenant.trim();
        
        List<String> readDataScopePaths = null;
        if (itemArr.length >= 2) {
            String readDataScopePathsStr = itemArr[1];
            if (StringUtils.isNotBlank(readDataScopePathsStr)) {
                readDataScopePaths = JSON.parseArray(readDataScopePathsStr, String.class);
                readDataScopePaths.sort(Comparator.comparing(String::length));
            }
        }
        
        List<String> updateDataScopePaths = null;
        if (itemArr.length >= 3) {
            String readDataScopePathsStr = itemArr[2];
            if (StringUtils.isNotBlank(readDataScopePathsStr)) {
                updateDataScopePaths = JSON.parseArray(readDataScopePathsStr, String.class);
                updateDataScopePaths.sort(Comparator.comparing(String::length));
            }
        }
        return Triple.of(tenant, readDataScopePaths, updateDataScopePaths);
    }
    
    /**
     * 从TenantDataScope信息字符串字符串中只抽取tenant
     *
     * @param tenantDataScopeStr TenantDataScope信息字符串
     *
     * @return 左(NonNull)-租户信息
     */
    @NonNull
    public static String extractTenantOnly(@NonNull String tenantDataScopeStr) {
        Objects.requireNonNull(tenantDataScopeStr, "tenant cannot be null.");
        String[] itemArr = tenantDataScopeStr.split("\\|");
        if (itemArr.length < 1) {
            throw new IllegalArgumentException("cannot extract-only tenant from tenantDataScopeStr -> " + tenantDataScopeStr);
        }
        return itemArr[0];
    }
}
